//====================================================
// L1 Memory interface, should lay above the block memory and handle reads/writes	4/29/2012
//=====================================================
//Q's: birdirectional pins possible? is write enable required on the ram...
//ToDo: rename variables to not be ridiculous
/*

Since I have no idea what I'm doing, I should probably say what I'm trying to do

This is supposed to be a wrapper for any block RAM core we use, because the (obnoxious) object-oriented part of me can't stand
putting everything into one file, and also likes to wrap 'primitives'. The block RAM module should communicate with this, along with the L1 controller. 

It should accept commands (mux) and return/do something.

All logic operations should be combinational and <1 clock cycle , and thus not be clocked. The actual read or write
should take a cycle. This wrapper should accept these commands:

1)readblocks(address)
	> reads a pair of blocks at two parallel RAM, returning all relevant information (data for pair, tags for pair, dirty bits for pair)
	> returns a 00 for a miss, or a 01 for a setindex-1 hit, or a 10 for a setindex-2 hit, and returns the data for both blocks in the set, and RR value for set

2)writeblock(address, data,bit index, bit dirty/clean)
	> writes the data to the specified set, at the specified index, marking it as either dirty or clean, marking it as valid, with the specified RR bit
	note: the controller must set all of the parameters correctly.. (dirty, valid, RR)
	> returns nothing - errorcode eventually
*/
module  l1memint(
mem_addr, mem_dout, l1_in_tag, sel, l1_in_rr, l1_in_valid, l1_in_dirty, l1_in_index, 
tagline_one_in, tagline_two_in, dataline_one_in, dataline_two_in, validbits, dirtybits, rr,
hitindex, dirtyindex, mem_din_1, mem_din_2,l1_out_rr, l1_out_valid, l1_out_dirty, mem_tagin_1, mem_tagin_2,
tagline_one_out,tagline_two_out,index_one_out,index_two_out,dataline_one_out, dataline_two_out, ram_rr, ram_valid,ram_dirty,ram_we
);
//=============Internal Constants======================
localparam TAGMSB = 31;
localparam TAGLSB = 14;
localparam INDEXMSB = 6;
localparam INDEXLSB = 2;
localparam OFFSETMSB = 1;
localparam OFFSETLSB = 0;
//------------Internal Variables-------
reg sel_1;
reg sel_2;
reg comparetag_1;
reg comparetag_2;
reg hit;
//-----------Input Ports---------------
////Global
//L1 controller to Memory Interface
input wire[31:0] mem_addr;
input wire[31:0] mem_dout;
input wire[TAGMSB:TAGLSB] l1_in_tag;
input wire[1:0] sel;
input wire l1_in_rr;
input wire l1_in_valid;
input wire l1_in_dirty;
input wire[INDEXMSB:INDEXLSB] l1_in_index;
//Block RAM to Memory Interface
input wire[TAGMSB:TAGLSB] tagline_one_in;		//Two-way set associative
input wire[TAGMSB:TAGLSB] tagline_two_in;		
input wire[31:0] dataline_one_in;
input wire[31:0] dataline_two_in;
input wire[1:0] dirtybits;
input wire[1:0] validbits;
input wire[1:0] rr;

//-----------Output Ports---------------
//Memory Interface to L1 controller
output reg hitindex;
output reg[1:0] dirtyindex;
output reg[31:0] mem_din_1;
output reg[31:0] mem_din_2;
output reg l1_out_rr;
output reg[1:0] l1_out_valid;
output reg[1:0] l1_out_dirty;
output reg[TAGMSB:TAGLSB]	mem_tagin_1;
output reg[TAGMSB:TAGLSB]	mem_tagin_2;

//Memory Interface to Block RAM module
output reg[TAGMSB:TAGLSB] tagline_one_out;		//Two-way set associative
output reg[TAGMSB:TAGLSB] tagline_two_out;		
output reg[INDEXMSB:INDEXLSB] index_one_out;
output reg[INDEXMSB:INDEXLSB] index_two_out;
output reg[31:0] dataline_one_out;
output reg[31:0] dataline_two_out;
output reg ram_rr;
output reg[1:0] ram_valid;
output reg[1:0] ram_dirty;
output reg ram_we;

//-------------Code Starts Here--------

always @ (sel)
begin : MUX
	//Read block
	if(sel == 2'b01) begin
		index_one_out = l1_in_index;
		index_two_out = l1_in_index;
		//This has problems with timing..
		comparetag_1 = tagline_one_in & l1_in_tag;
		comparetag_2 = tagline_two_in & l1_in_tag;
		sel_1 = comparetag_1 & validbits[0];
		sel_2 = comparetag_2 & validbits[1];
		hit = sel_1 | sel_2;	
		hitindex <= {sel_1,hit};	//{lowerbit,upperbit} or the opposite???
		dataline_one_out <= dataline_one_in;
		dataline_two_out <= dataline_two_in;
		l1_out_rr <= rr;
		l1_out_valid <= validbits;
		l1_out_dirty <= dirtybits;
		mem_tagin_1 <= tagline_one_in;
		mem_tagin_2 <= tagline_two_in;
	//Write block
	end else if(sel == 2'b10) begin
		if(l1_in_index == 0) begin
			mem_din_1 <= mem_dout;
			ram_valid[0] <= l1_in_valid;
			ram_dirty[0] <= l1_in_dirty;	
			tagline_one_out <= l1_in_tag;
		end else begin
			mem_din_2 <= mem_dout;
			ram_valid[1] <= l1_in_valid;
			ram_dirty[1] <= l1_in_dirty;		
			tagline_two_out <= l1_in_tag;
		end
		ram_rr <= l1_in_rr;
		ram_we <= 1;
	end 
end
endmodule //End Of Module l1memint
